package main

import (
	"bytes"
	"encoding/json"
	"io/ioutil"
	"log"
	"os"
	"sync/atomic"
	"time"

	"github.com/go-vgo/robotgo"
	hook "github.com/robotn/gohook"
)

type ActionsData struct {
	Clicks  []ClickRecord
	Trigers []TrigerRecord
}

type TrigerRecord struct {
	X      int
	Y      int
	Img    []byte
	Clicks []ClickRecord
}

func newTriger() (res *TrigerRecord) {
	res = &TrigerRecord{}
	res.X, res.Y = robotgo.GetMousePos()
	robotgo.MoveMouse(res.X+10, res.Y+10)
	img := robotgo.CaptureScreen(res.X-2, res.Y-2, 5, 5)
	robotgo.MoveMouse(res.X, res.Y)
	res.Img = robotgo.ToBitmapBytes(img)
	res.Clicks = []ClickRecord{}

	return
}

func record(filename string, out IGui) {
	defer out.OnEnd()
	var actions = &ActionsData{Clicks: []ClickRecord{}, Trigers: []TrigerRecord{}}
	var triger *TrigerRecord

	var end = make(chan int, 1)
	var recType int = 0
	var last int64
	out.Println(`按 alt-1 开始记录鼠标左键点击，按alt-9暂停。
按 alt-2 新建触发器，触发条件是鼠标所在坐标周围5X5像素点，然后记录相应的鼠标左键点击动作，按 alt-9 暂时保存触发器。
随时可以按 alt-0 保存记录到文件 `)
	robotgo.EventHook(hook.KeyDown, []string{"1", "alt"}, func(e hook.Event) {
		if recType != 0 {
			return
		}
		out.Println("开始记录")
		out.Println("按 alt-0 结束")
		recType = 1
		last = time.Now().UnixNano()
	})

	robotgo.EventHook(hook.KeyDown, []string{"0", "alt"}, func(e hook.Event) {
		out.Println("结束记录并保存到:" + filename)

		end <- 1
	})
	robotgo.EventHook(hook.KeyDown, []string{"9", "alt"}, func(e hook.Event) {
		out.Println("暂停记录")
		if recType == 2 {
			actions.Trigers = append(actions.Trigers, *triger)
		}

		recType = 0
	})
	robotgo.EventHook(hook.KeyDown, []string{"2", "alt"}, func(e hook.Event) {
		if recType != 0 {
			return
		}
		out.Println("设置动作触发")

		recType = 2
		triger = newTriger()
		out.Printf("Triger:%d,%d\n", triger.X, triger.Y)
		last = time.Now().UnixNano()
	})
	robotgo.EventHook(hook.MouseDown, []string{}, func(e hook.Event) {
		if e.Button == robotgo.MouseMap["left"] {
			delay := e.When.UnixNano() - last
			last = e.When.UnixNano()
			x := int(e.X)
			y := int(e.Y)
			switch recType {
			case 1:
				actions.Clicks = append(actions.Clicks, ClickRecord{Delay: delay, X: x, Y: y})
				out.Printf("Click:%d,%d,%d\n", delay, x, y)
			case 2:
				triger.Clicks = append(triger.Clicks, ClickRecord{Delay: delay, X: x, Y: y})
				out.Printf("Triger click:%d,%d,%d\n", delay, x, y)
			}

		}

	})

	ch := robotgo.EventStart()

	res := robotgo.EventProcess(ch)

	<-end

	robotgo.EventEnd()
	<-res

	fp, err := os.Create(out.MakeRecordPath(filename))
	if err != nil {
		panic(err)
	}
	defer fp.Close()
	data, err := json.Marshal(actions)
	if err != nil {
		panic(err)
	}
	fp.Write(data)
}

type ClickRecord struct {
	Delay int64
	X     int
	Y     int
}

func getRecords(fn string) *ActionsData {
	data, err := ioutil.ReadFile(fn)
	if err != nil {
		panic(err)
	}
	res := &ActionsData{}
	err = json.Unmarshal(data, res)
	if err != nil {
		panic(err)
	}
	return res
}

func play(fn string, count int, out IGui) {
	defer out.OnEnd()
	log.Println("play", fn)
	records := getRecords(out.MakeRecordPath(fn))
	max := len(records.Clicks)

	var brk int32 = 0
	out.Println("执行:" + fn)
	out.Println("按 alt-1 开始执行鼠标点击序列和触发器")
	out.Println("按 alt-0 提前结束")
	robotgo.AddEvents("1", "alt")

	go func() {
		ok := robotgo.AddEvents("0", "alt")
		if ok {
			atomic.StoreInt32(&brk, 1)
		}
		out.Println("收到提前结束信号")
	}()

	if max == 0 {
		goto TRIGERS
	}

	out.Printf("自动点击鼠标 %d 次循环\n", count)
	for i := 0; i < count; i++ {
		for j := 0; j < max; j++ {
			if atomic.LoadInt32(&brk) == 1 {
				break
			}
			select {
			case <-out.Context().Done():
				break
			default:
			}
			time.Sleep(time.Duration(records.Clicks[j].Delay))
			robotgo.MoveClick(records.Clicks[j].X, records.Clicks[j].Y, "left", false)
		}
	}
TRIGERS:
	if len(records.Trigers) > 0 {
		out.Println("开始监听触发事件")
	} else {
		return
	}
	var n int = 0
	for {
		for i := range records.Trigers {
			img := robotgo.CaptureScreen(records.Trigers[i].X-2, records.Trigers[i].Y-2, 5, 5)
			data := robotgo.ToBitmapBytes(img)
			if bytes.Compare(data, records.Trigers[i].Img) == 0 {
				n++
				out.Printf("触发：%d,%d\n", records.Trigers[i].X, records.Trigers[i].Y)
				for j := 0; j < len(records.Trigers[i].Clicks); j++ {
					time.Sleep(time.Duration(records.Trigers[i].Clicks[j].Delay))
					if atomic.LoadInt32(&brk) == 1 {
						break
					}
					robotgo.MoveClick(records.Trigers[i].Clicks[j].X, records.Trigers[i].Clicks[j].Y, "left", false)
				}
			}
		}
		time.Sleep(time.Second)
		if atomic.LoadInt32(&brk) == 1 {
			break
		}
		if n >= count {
			break
		}
		select {
		case <-out.Context().Done():
			break
		default:
		}
	}
}

func main() {
	log.SetFlags(log.Lshortfile | log.LstdFlags)
	window := NewAppGui()

	window.Show()
}
